home *** CD-ROM | disk | FTP | other *** search
-
- SiFLyiNG
- Tutorial #10
-
- ___________________________________________________________________________
-
- Target : Liquid Crackme 2
- d/l it on Http://crackmes.cjb.net
- Protection type : Code, red herrings ;)
- Level : Basis and discernment are needed
- Tools needed : SoftIce 4 or 3.xx
- Basis of cracking of course
- A brain
- Some punk mp3 like Rancid or Wizo
- A drink could be very helpful :)
-
- ___________________________________________________________________________
-
- Before beginning...
-
- Hope you've read my tut 9 on the previous -and first- Liquid Crackme.
- This one is based on a code protection. The checking seems very long but
- there are lots of red herrins (hope it must be written like that...). In fact,
- only 3 chars of the entered code are really checked, that's why i told you
- need discernment to find the 'useful' and interesting checking routine.
- I think i've told enough for this introduction. We're now ready to
- get rid off this crackme :)
- ___________________________________________________________________________
-
- The essay...
-
- Run the proggie and you see an unique textbox to complete. Let's
- enter a dummy code : '12345678'. We'll suppose in the crackme that the name
- is separated in 8 parts : X1X2X3X4X5X6X7X8
- Now 'Bpx hmemcpy' is SoftIce and F5 to come back to the crackme.
- Here you press the 'Check!' button. Boom, we're back to SoftIce. Press F11 to
- return to the caller, and F12 until you see this at the bottom of the code
- window :
-
- SERIAL!CODE+00026261
-
- You should now see this piece of code :
-
- :00427261 call 00411AC8 ; this call gets the entered code
- :00427266 cmp dword ptr [ebp-04], 00000000 ; [ebp-04] contains the lenght of
- the name, so the lenght is compared to 00
- :0042726A jne 00427286 ; jump is lenght>0
-
- So the following routine is used when no name was entered :
-
- :0042726C push 00000000
- :0042726E mov cx, word ptr [00427610]
- :00427275 mov dl, 02
- :00427277 mov eax, 0042761C ; points to "You must enter something!"
- :0042727C call 00426CAC ; displays a message box
- :00427281 jmp 004275E4 ; jump out of the routine
-
- The few previous lines are also used to prevent that no name was
- entered in the TextBox. But we entered '12345678' so we jump over this
- routine and the crackme go on checking the code:
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:0042726A(C) <=> previous jump if name entered
- |
- :00427286 lea edx, dword ptr [ebp-04]
- :00427289 mov eax, dword ptr [esi+000001C0]
- :0042728F call 00411AC8
-
- NB : all the call to 411AC8 are getting a string. So i advise
- to disable the breakpoint by 'bd *', otherwise you'll have each time a bpx
- on hmemcpy !!!
-
- :00427294 mov eax, dword ptr [ebp-04] ; eax points to the name
- :00427297 movzx eax, byte ptr [eax] ; eax = X1
- :0042729A push eax ; push the value of 1st char of code
- :0042729B lea edx, dword ptr [ebp-08]
- :0042729E mov eax, dword ptr [esi+000001AC]
- :004272A4 call 00411AC8 ; get a 'magic' string
- :004272A9 mov eax, dword ptr [ebp-08] ; eax points to this string
-
- Another break : the string that i call the 'magic' string is only the
- following string: "Registration Information:" which is used all along the
- verification. Note you can see this string in the main window of the crackme,
- in the upper left corner.
-
- :004272AC movzx eax, byte ptr [eax+07] ; eax = value of 8th char of magic
- ; string = value of 'a' = 61h
- :004272B0 pop edx ; pop the value of 1st char of code
- :004272B1 xor edx, eax ; edx = X1 xor 61h
- :004272B3 mov dword ptr [ebx], edx ; store edx in [ebx]
- :004272B5 lea edx, dword ptr [ebp-04]
- :004272B8 mov eax, dword ptr [esi+000001AC]
- :004272BE call 00411AC8 ; get the magic string
- :004272C3 mov eax, dword ptr [ebp-04]
- :004272C6 movzx eax, byte ptr [eax+0D] ; eax = value of 14th char of the
- ; magic string = 'I' = 49h
- :004272CA xor eax, 00000080 ; eax = 49h xor 80h = C9
- :004272CF mov dword ptr [edi], eax ; store eax in [edi]
- :004272D1 mov eax, dword ptr [ebx] ; eax = X1 xor 61h
- :004272D3 not eax ; eax = not(X1 xor 61h)
- :004272D5 cmp eax, 00000037 ; cmp eax to 37
- :004272D8 jne 004272DF ; jump if they are differents
- :004272DA call 004271EC ; call ???
-
- Pfff... what have we got in here ?
- Eax = not(X1 xor 61) must be equal to 37 not to jump ... so let's
- calculate X1:
-
- X1 xor 61h = NOT 37h => X1 = 61h xor FFFFFFC8h = FFFFFFA9h
-
- Wtf ?!? Hey how X1 can be equal to FFFFFFC8h if ascii value stop to FF ?
- Hummm i suggest to look closer... let's reverse the flag not to jump and make
- the crackme believe they are equals ('r fl z'). Arghh! a messagebox tell us:
- "Nop! Keep working". So you easily deduce the comparison is a red herring.
- But you wonder : "What's those red herrings ???" I use to answer a
- definition made by EB in one of his project :
- "Red herring is something like sending you on a useless path far from the
- correct spot. 8)"
-
- You must understand now... we have to avoid all the call 004271EC
- that displays each time a bad cracker message box. I mean, we have to ignore
- these particular structure :
-
- jne XXXXXXXX
- call 004271EC ; display bad cracker message box
-
- Woohh it eliminates lot of job !!! yes so we can now find the really
- interesting part of the code !
- So let's continue :
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:004272D8(C) => this jump is automatically taken
- |
- :004272DF lea edx, dword ptr [ebp-04]
- :004272E2 mov eax, dword ptr [esi+000001C0]
- :004272E8 call 00411AC8
- :004272ED mov eax, dword ptr [ebp-04]
- :004272F0 movzx eax, byte ptr [eax+01]
- :004272F4 push eax
- :004272F5 lea edx, dword ptr [ebp-08]
- :004272F8 mov eax, dword ptr [esi+000001AC]
- :004272FE call 00411AC8
- :00427303 mov eax, dword ptr [ebp-08]
- :00427306 movzx eax, byte ptr [eax+06]
- :0042730A pop edx
- :0042730B and edx, eax
- :0042730D mov dword ptr [ebx], edx
- :0042730F lea edx, dword ptr [ebp-04]
- :00427312 mov eax, dword ptr [esi+000001AC]
- :00427318 call 00411AC8
- :0042731D mov eax, dword ptr [ebp-04]
- :00427320 movzx eax, byte ptr [eax+0E]
- :00427324 xor eax, 0000000E
- :00427327 mov dword ptr [edi], eax
- :00427329 mov eax, dword ptr [ebx]
- :0042732B not eax
- :0042732D cmp eax, dword ptr [edi]
- :0042732F jne 00427336 ; arghhh the famous structure
- ; but it automatically jumps
- :00427331 call 004271EC
-
-
- Hey, this method prevents us from studying dummy code :) Just ignore
- the previous part and continue and this time it becomes interesting:
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:0042732F(C) => this jump is automatically taken
- |
- :00427336 lea edx, dword ptr [ebp-04]
- :00427339 mov eax, dword ptr [esi+000001C0]
- :0042733F call 00411AC8 ; gets the entered code
- :00427344 mov eax, dword ptr [ebp-04] ; eax points to the code
- :00427347 movzx eax, byte ptr [eax+02] ; eax = X3
- :0042734B push eax ; push eax on the stack
- :0042734C lea edx, dword ptr [ebp-08]
- :0042734F mov eax, dword ptr [esi+000001AC]
- :00427355 call 00411AC8 ; get the magic string
- :0042735A mov eax, dword ptr [ebp-08] ; eax points to the magic string
- :0042735D movzx eax, byte ptr [eax+05] ; eax=value of 6th char of the
- ; magic string = 't' = 74h
- :00427361 pop edx ; pop X3 in edx
- :00427362 xor edx, eax ; edx = X3 xor 74h
- :00427364 mov dword ptr [ebx], edx ; store edx to [ebx]
- :00427366 lea edx, dword ptr [ebp-04]
- :00427369 mov eax, dword ptr [esi+000001AC]
- :0042736F call 00411AC8 ; gets the magic string
- :00427374 mov eax, dword ptr [ebp-04] ; eax points to the magic string
- :00427377 movzx eax, byte ptr [eax+0F] ; eax= value of 16th char of the
- ; magic string = 'f' = 66h
- :0042737B xor eax, 00000044 ; eax = 66h xor 44h = 22h
- :0042737E mov dword ptr [edi], eax ; store eax in edi
- :00427380 mov eax, dword ptr [ebx] ; eax = [ebx] = X3 xor 74h
- :00427382 cmp eax, dword ptr [edi] ; cmp eax to [edi]
- :00427384 je 0042738B ; jump if equal
- :00427386 call 004271EC ; <= bad cracker msgbox
-
- Hey ! it's differents from the previous cmp, isn't it ? Now it's a je
- (means jump if equal), so the jump is taken only if eax=[edi] and it avoids
- the bad cracker message, and continue the verification.
- So we must have :
-
- eax=[edi] <=> X3 xor 74h=22h <=> X3=74h xor 22h=56h
-
- However 56h is the ASCII code for char 'V'. Hey it simply means that
- X3 must be 'V' and the code X1X2VX4X5X6X7X8... quite a nice beginning :)
- Let's continue:
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:00427384(C) => this jump must be taken !!!
- |
- :0042738B lea edx, dword ptr [ebp-04]
- :0042738E mov eax, dword ptr [esi+000001C0]
- :00427394 call 00411AC8
- :00427399 mov eax, dword ptr [ebp-04]
- :0042739C movzx eax, byte ptr [eax+03]
- :004273A0 push eax
- :004273A1 lea edx, dword ptr [ebp-08]
- :004273A4 mov eax, dword ptr [esi+000001AC]
- :004273AA call 00411AC8
- :004273AF mov eax, dword ptr [ebp-08]
- :004273B2 movzx eax, byte ptr [eax+04]
- :004273B6 pop edx
- :004273B7 and edx, eax
- :004273B9 mov dword ptr [ebx], edx
- :004273BB lea edx, dword ptr [ebp-04]
- :004273BE mov eax, dword ptr [esi+000001AC]
- :004273C4 call 00411AC8
- :004273C9 mov eax, dword ptr [ebp-04]
- :004273CC movzx eax, byte ptr [eax+10]
- :004273D0 xor eax, 0000000E
- :004273D3 mov dword ptr [edi], eax
- :004273D5 mov eax, dword ptr [ebx]
- :004273D7 not eax
- :004273D9 cmp eax, dword ptr [edi]
- :004273DB jne 004273E2 ; and the famous structure again :)
- :004273DD call 004271EC
-
- Hummm... not interesting... another red herring. Let's see what's
- afterwards :
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:004273DB(C) => this jump is automatically taken
- |
- :004273E2 lea edx, dword ptr [ebp-04]
- :004273E5 mov eax, dword ptr [esi+000001C0]
- :004273EB call 00411AC8
- :004273F0 mov eax, dword ptr [ebp-04]
- :004273F3 movzx eax, byte ptr [eax+04]
- :004273F7 push eax
- :004273F8 lea edx, dword ptr [ebp-08]
- :004273FB mov eax, dword ptr [esi+000001AC]
- :00427401 call 00411AC8
- :00427406 mov eax, dword ptr [ebp-08]
- :00427409 movzx eax, byte ptr [eax+03]
- :0042740D pop edx
- :0042740E xor edx, eax
- :00427410 mov dword ptr [ebx], edx
- :00427412 lea edx, dword ptr [ebp-04]
- :00427415 mov eax, dword ptr [esi+000001AC]
- :0042741B call 00411AC8
- :00427420 mov eax, dword ptr [ebp-04]
- :00427423 movzx eax, byte ptr [eax+11]
- :00427427 xor eax, 00000057
- :0042742A mov dword ptr [edi], eax
- :0042742C mov eax, dword ptr [ebx]
- :0042742E not eax
- :00427430 cmp eax, 00000025
- :00427433 jne 0042743A ; the famous structure again and again :)
- :00427435 call 004271EC
-
- Let's ignore this piece of code too: red herring !!! Let's continue
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:00427433(C) => automatically taken
- |
- :0042743A lea edx, dword ptr [ebp-04]
- :0042743D mov eax, dword ptr [esi+000001C0]
- :00427443 call 00411AC8
- :00427448 mov eax, dword ptr [ebp-04]
- :0042744B movzx eax, byte ptr [eax+05]
- :0042744F push eax
- :00427450 lea edx, dword ptr [ebp-08]
- :00427453 mov eax, dword ptr [esi+000001AC]
- :00427459 call 00411AC8
- :0042745E mov eax, dword ptr [ebp-08]
- :00427461 movzx eax, byte ptr [eax+02]
- :00427465 pop edx
- :00427466 and edx, eax
- :00427468 mov dword ptr [ebx], edx
- :0042746A lea edx, dword ptr [ebp-04]
- :0042746D mov eax, dword ptr [esi+000001AC]
- :00427473 call 00411AC8
- :00427478 mov eax, dword ptr [ebp-04]
- :0042747B movzx eax, byte ptr [eax+12]
- :0042747F xor eax, 0000000C
- :00427482 mov dword ptr [edi], eax
- :00427484 mov eax, dword ptr [ebx]
- :00427486 not eax
- :00427488 cmp eax, dword ptr [edi]
- :0042748A jne 00427491 ; arghhhh another time the same structure
- :0042748C call 004271EC
-
- Ok another red herring !!! but the next piece of code is a good one
- time. The jne is no more a jne, but a je, so we have to study it attentively:
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:0042748A(C) => automatically taken too
- |
- :00427491 lea edx, dword ptr [ebp-04]
- :00427494 mov eax, dword ptr [esi+000001C0]
- :0042749A call 00411AC8 ; get the entered code
- :0042749F mov eax, dword ptr [ebp-04] ; eax points to the code
- :004274A2 movzx eax, byte ptr [eax+06] ; eax = X7
- :004274A6 push eax ; push eax on the stack
- :004274A7 lea edx, dword ptr [ebp-08]
- :004274AA mov eax, dword ptr [esi+000001AC]
- :004274B0 call 00411AC8 ; get the magic string
- :004274B5 mov eax, dword ptr [ebp-08] ; eax points to the magic string
- :004274B8 movzx eax, byte ptr [eax+01] ; eax = value of 2nd char of the
- ; magic string = 'e' = 65h
- :004274BC pop edx ; pop edx => edx = X7
- :004274BD xor edx, eax ; edx = X7 xor 65h
- :004274BF mov dword ptr [ebx], edx ; store edx in [ebx]
- :004274C1 lea edx, dword ptr [ebp-04]
- :004274C4 mov eax, dword ptr [esi+000001AC]
- :004274CA call 00411AC8 ; get the magic string
- :004274CF mov eax, dword ptr [ebp-04] ; eax points to the magic string
- :004274D2 movzx eax, byte ptr [eax+13] ; eax = value of 20th char of the
- ; magic string = 'a' = 61h
- :004274D6 xor eax, 00000049 ; eax = 61h xor 49h = 28h
- :004274D9 mov dword ptr [edi], eax ; store eax in [edi]
- :004274DB cmp dword ptr [ebx], 00000028 ; cmp [ebx] to 28h
- :004274DE je 004274E5 ; hey a je this time :)
- :004274E0 call 004271EC ; <= bad cracker message
-
- You easily understand that the jump must be taken here to avoid this
- boring bad cracker message. So we mus have to take the jump:
-
- [ebx]=28 <=> X7 xor 65h=28h <=> X7=65h xor 28h=4Dh
-
- However 4D is the ascii hexa code for 'M'. So X7 must be 'M' and the
- serial now becomes X1X2VX4X5X6MX8... Let's see the following :
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:004274DE(C) => this jump must be taken
- |
- :004274E5 lea edx, dword ptr [ebp-04]
- :004274E8 mov eax, dword ptr [esi+000001C0]
- :004274EE call 00411AC8 ; get the entered code
- :004274F3 mov eax, dword ptr [ebp-04] ; eax points to the code
- :004274F6 movzx eax, byte ptr [eax+07] ; eax = X8
- :004274FA push eax ; push eax
- :004274FB lea edx, dword ptr [ebp-08]
- :004274FE mov eax, dword ptr [esi+000001AC]
- :00427504 call 00411AC8 ; get the magic string
- :00427509 mov eax, dword ptr [ebp-08] ; eax points to the string
- :0042750C movzx eax, byte ptr [eax] ; eax = value of 1st char of the
- ; magic string = 'R' = 52h
- :0042750F pop edx ; pop edx => edx = X8
- :00427510 and edx, eax ; edx = X8 and 52h
- :00427512 mov dword ptr [ebx], edx ; edx is stored in [ebx]
- :00427514 lea edx, dword ptr [ebp-04]
- :00427517 mov eax, dword ptr [esi+000001AC]
- :0042751D call 00411AC8 ; get the magic string
- :00427522 mov eax, dword ptr [ebp-04] ; eax points to the magic string
- :00427525 movzx eax, byte ptr [eax+14] ; eax = value of 21th char of the
- ; magic string = 't' = 74h
- :00427529 xor eax, 00000024 ; eax = 74h xor 24h = 50h
- :0042752C mov dword ptr [edi], eax ; eax is stored in [edi]
- :0042752E cmp dword ptr [ebx], 00000050 ; cmp [ebx] to 50h
- :00427531 je 00427538 ; jump if they are equal
- :00427533 call 004271EC ; bad cracker message
-
- Interesting part too... {ebx] is finally compared to 50h, and they
- must be equal to take the jump, what is necessary. So we must have:
-
- [ebx]=50h <=> X8 and 52h=50h <=> X8= 50h and 52h=50h
-
- And we know that 50h is the ascii value for the char 'P'
-
- We know now that the serial must look like X1X2VX4X5X6MP, where X1,X2... are
- variables.
-
- Let's see what happen afterwards :
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:00427531(C) => this jump must be taken !!!
- |
- :00427538 lea edx, dword ptr [ebp-04]
- :0042753B mov eax, dword ptr [esi+000001C0]
- :00427541 call 00411AC8 ; get the entered code
- :00427546 mov eax, dword ptr [ebp-04] ; eax points to the code
- :00427549 cmp byte ptr [eax+08], 45 ; cmp X9 to 45h
- :0042754D je 0042755E ; jump to 42755E if equal
- :0042754F mov eax, dword ptr [esi+000001B4]
- :00427555 mov bx, FFF5
- :00427559 call 00402A0C ; display About box
-
- Here X9 must be equal to 45h, i.e. to 'E' in order to jump over
- the call that display the msgbox. I imagine that we have to jump and avoid
- the about box. So the serial become X1X2VX4X5X6PME
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:0042754D(C) ; we arrive here after the jump
- |
- :0042755E lea edx, dword ptr [ebp-04]
- :00427561 mov eax, dword ptr [esi+000001C0]
- :00427567 call 00411AC8 ; get the entered code
- :0042756C mov eax, dword ptr [ebp-04] ; eax points to the code
- :0042756F cmp byte ptr [eax+09], 72 ; cmp X10 to 72h
- :00427573 je 00427584 ; jump if equal
- :00427575 mov eax, dword ptr [esi+000001B4]
- :0042757B mov bx, FFF5
- :0042757F call 00402A0C ; display the About Box
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:00427573(C)
- |
- :00427584 lea edx, dword ptr [ebp-04]
- :00427587 mov eax, dword ptr [esi+000001C0]
- :0042758D call 00411AC8 ; get the entered code
- :00427592 mov eax, dword ptr [ebp-04] ; eax points to the code
- :00427595 cmp byte ptr [eax+0A], 54 ; cmp X11 to 54h
- :00427599 je 004275AA ; jump if equal
- :0042759B mov eax, dword ptr [esi+000001B4]
- :004275A1 mov bx, FFF5
- :004275A5 call 00402A0C ; display the about box
-
- * Referenced by a (U)nconditional or (C)onditional Jump at Address:
- |:00427599(C)
- |
- :004275AA lea edx, dword ptr [ebp-04]
- :004275AD mov eax, dword ptr [esi+000001C0]
- :004275B3 call 00411AC8 ; get the entered code
- :004275B8 mov eax, dword ptr [ebp-04] ; eax points to the code
- :004275BB cmp byte ptr [eax+0B], 65 ; cmp X12 to 65h
- :004275BF je 004275D0 ; jump if equal
- :004275C1 mov eax, dword ptr [esi+000001B4]
- :004275C7 mov bx, FFF5
- :004275CB call 00402A0C ; display the about box
-
- Here are the last lines of the verification of the serial. We can
- deduce the last char of the good code :
-
- X9 = 45h = 'E'
- X10= 72h = 'r'
- X11= 54h = 'T'
- X12= 65h = 'e'
-
- and the serial finally becomes X1X2VX4X5X6PMErTe, where X1,X2,...X6
- are variables
-
- Enter any code like : 12V456MPErTe or SiVFLyMPErTeiNG
- Then the crackme display a little message box and no About box is displayed :
-
- "Cracked"
- "Great job cracker! Well done!"
- "Mail me..."
-
- Hey, cracked cracked !!! ;)
-
- ___________________________________________________________________________
-
- The end...
-
- Waouhh... this tutorial was quite long i know... i believe i could
- have made it shorter but this is not really difficult and there are lots of
- red herrings (useless pieces of code !!!). I could have erase them and ignore
- them even in the tutor but i wanted to show all the steps i've followed...
- If you have questions, or critics, just mail me...
-
- SiFLyiNG
- siflying@ifrance.com
-
- Greetz : ACiD BuRN, Eternal Bliss, Magic Raphoun, Lucifer48,
- Skymarshall, Volatility, VisionZ, AB4DS
- all the authors of crackmes and tutorials
- and Liquid of course for his nice crackme :)
-
- PS : I'm looking for Win32asm source for keygen and crackmes... if you have
- some please mail them...
-
-